rtu = {}

--报文table
local MessageMap =
{
    Status = "0",
    Variable = {}
}

local Variableindex = 1
--数据解析table
VariableMap =
{
    Status = "1",
    Variable = {}
}

function TestEnv() --true:测试环境  false:生产环境
    if (string.find(package.path, "utils") ~= nil)
    then
        return false
    else
        return true
    end
end

function Luaprint(str) --只在测试环境下的print
    if (TestEnv() == true)
    then
        print(str)
    end
end

function HexToFloat(hexString)
    if hexString == nil then
        return 0
    end
    local t = type(hexString)
    if t == "string" then
        hexString = tonumber(hexString, 16)
    end

    local hexNums = hexString

    local sign = math.modf(hexNums / (2 ^ 31))

    local exponent = hexNums % (2 ^ 31)
    exponent = math.modf(exponent / (2 ^ 23)) - 127

    local mantissa = hexNums % (2 ^ 23)

    for i = 1, 23 do
        mantissa = mantissa / 2
    end
    mantissa = 1 + mantissa
    --  print(mantissa)
    local result = (-1) ^ sign * mantissa * 2 ^ exponent
    return tonumber(string.format('%.3f', result))
end

--功能：modbus读数据组报文
--sAddr      设备地址
--funCode    功能码
--startAddr  寄存器起始地址
--regCnt     寄存器数量
--isContinue:是否继续组下一条报文   true：是  false：否，当前是最后一条报文
--功能码适用范围
--01 读线圈寄存器
--02 读离散输入寄存器
--03 读保持寄存器
--04 读输入寄存器
function rtu.ReadData(sAddr,funCode,startAddr,regCnt,isCcontinue)
    local crc
    local requestADU = {}

    requestADU[1] = sAddr                       --通信地址
    requestADU[2] = funCode                     --功能码
    requestADU[3] = math.modf(startAddr/256)
    requestADU[4] = startAddr%256               --寄存器起始地址
    requestADU[5] = math.modf(regCnt/256)
    requestADU[6] = regCnt%256               --寄存器个数

    local VariableMapTemp = 
    {
        Variable = requestADU
    }
    crc = GetCRCModbus(VariableMapTemp)
    if (crc == nil) then
        return MessageMap
    end
    requestADU[7] = math.modf(crc % 256) --CRC校验
    requestADU[8] = math.modf(crc / 256)
    if isCcontinue then
        MessageMap.Status = "1"
    else
        MessageMap.Status = "0"
    end

    MessageMap.Variable = requestADU
    return MessageMap
end

--[单个]写数据组报文
--data               要写的数据
--功能码适用范围
--05 写单个线圈
--06 写单个保持寄存器
--turning赋值为表时  数据对应表
--turning[1]  上层数据
--turning[2]  设备对应数据
--turning赋值为数字时 下发数据的倍数  Value = Value * turning
function rtu.WriteData(sAddr,funCode,startAddr,data,turning)
    local crc
    local requestADU = {}

    local Value = tonumber(data)
    if type(turning) == "table" then
        for i = 1,#turning[1] do
            if Value == turning[1][i] then
                Value = turning[2][i]
            end
            break
        end
    end
    if type(turning) == "number" then
        Value = Value * turning
    end

    local ValueHigh = math.modf( Value/256 )  --要写的数据高位
    local ValueLow = Value % 256              --要写的数据低位
    requestADU[1] = sAddr                     --通信地址
    requestADU[2] = funCode                   --功能码
    requestADU[3] = math.modf(startAddr/256)  --寄存器起始地址高位
    requestADU[4] = startAddr%256             --寄存器起始地址低位
    requestADU[5] = ValueHigh
    requestADU[6] = ValueLow
    local VariableMapTemp =
    {
        Variable = requestADU
    }

    crc = GetCRCModbus(VariableMapTemp)
    if (crc == nil) then
        return MessageMap
    end

    requestADU[7] = math.modf(crc % 256)
    requestADU[8] = math.modf(crc / 256)

    MessageMap.Status = "0"
    MessageMap.Variable = requestADU

    return MessageMap
end

--0x10 写单个数据
--reflectTable  数据对应表
--reflectTable[1]  上层要下发数据
--reflectTable[2]  对应到设备的数据
function rtu.WriteData0x10(sAddr,startAddr,data,reflectTable)
    local crc
    local requestADU = {}

    local Value = tonumber(data)
    if reflectTable then
        for i = 1,#reflectTable[1] do
            if Value == reflectTable[1][i] then
                Value = reflectTable[2][i]
            end
            break
        end
    end
    local ValueHigh = math.modf( Value/256 ) --要写入的数据高位
    local ValueLow = Value % 256             --要写入的数据低位
    requestADU[1] = sAddr                    --通信地址
    requestADU[2] = 0x10                     --功能码
    requestADU[3] = math.modf(startAddr/256) --寄存器起始地址高位
    requestADU[4] = startAddr%256            --寄存器起始地址低位
    requestADU[5] = 0x00
    requestADU[6] = 0x01
    requestADU[7] = 0x02
    requestADU[8] = ValueHigh
    requestADU[9] = ValueLow
    local VariableMapTemp =
    {
        Variable = requestADU
    }

    crc = GetCRCModbus(VariableMapTemp)
    if (crc == nil) then
        return MessageMap
    end

    requestADU[10] = math.modf(crc % 256)
    requestADU[11] = math.modf(crc / 256)

    MessageMap.Status = "0"
    MessageMap.Variable = requestADU

    regAddr = startAddr
    return MessageMap
end

--crc校验
--@return  true：校验正确  false：校验错误
function rtu.CRCCheck(starIndex,endIndex,rxbuf,rxCRC)
    local VariableMapTemp =
    {
        Variable = {}
    }
    for i=starIndex,endIndex do
        table.insert(VariableMapTemp.Variable,rxbuf[i])
    end

    local crc = GetCRCModbus(VariableMapTemp)
    if (crc ==nil or crc ~=rxCRC)then
        Luaprint("crc校验值不匹配")
        return false
    end
    return true
end

function DecimalAnalysis(data)
    return math.modf(data/0x10)*10+(data%0x10)
end

--rxdata 数据table 数据个数可变 2/4个字节
--format 数据解析格式
-------  1代表数据位高低按照寄存器顺序由高到低 {0x12,0x34,0x56,0x78} ==> 0x12345678 
------- -1代表数据位高低按照字节顺序由低到高   {0x12,0x34,0x56,0x78} ==> 0x78563412 
-------  2代表数据位高低按照寄存器顺序由低到高 {0x12,0x34,0x56,0x78} ==> 0x56781234
-------  0代表IEEE754转float保留三位小数
-------  3代表按照十进制来解析                {0x12,0x34,0x56,0x78} ==> 12345678
--turning 当turning时表时 数据对应表 
-------turning[1]  要对应的数据
-------turning[2]  采集上来的数据 
-------当turning为数字时 turning是解析的数据要乘的系数
-------当turning为boollen时(true/false) 表示解析出来的数据不添加到变量表 只return
function rtu.GetByteData(rxdata,format,variableName,turning)
    local data = 0.0
    if format == 1 then
        for i = 1,#rxdata do
            data = data + rxdata[i]*0x100^(#rxdata - i)
        end
    elseif format == 0 then
        for i = 1,#rxdata do
            data = data + rxdata[i]*0x100^(#rxdata - i)
        end
        data = HexToFloat(data)
    elseif format == 2 then
        for i = 1,#rxdata,2 do
            data = data + rxdata[i]*0x100^(i) + rxdata[i+1]*0x100^(i-1)
        end
    elseif format == 3 then
        for i = 1,#rxdata do
            data = data + DecimalAnalysis(rxdata[i])*100^(#rxdata-i)
        end
    elseif format == -1 then
        --要做修改
        for i = 1,#rxdata do
            data = data + rxdata[i]*0x100^(i-1)
        end
    end

    if type(turning)=="table" then
        for i = 1,#turning[2] do
            if data == turning[2][i] then
                data = turning[1][i]
            end
            break
        end
    end

    if type(turning)=="number" then
        data = data * turning
    end

    if type(turning)=="boolean" then
        return data
    end

    VariableMap.Variable[Variableindex] = utils.AppendVariable(Variableindex,variableName,data,data)
    Variableindex = Variableindex+1
    return data
end

--rxdata 数据字节
--index  所需数据在字节中的位置(0--7)
--variableName 变量名
function  rtu.GetBitData(rxdata,index,variableName)
    local data = 0
    if utils.And(rxdata,2^index) == 2^index then
        data = 1
    elseif utils.And(rxdata,2^index)== 0 then
        data = 0
    end
    VariableMap.Variable[Variableindex] = utils.AppendVariable(Variableindex,variableName,data,data)
    Variableindex = Variableindex+1
    return data
end

return rtu